package com.anycc.cloud.core.service.impl;

import com.anycc.cloud.common.dto.query.PagingRequest;
import com.anycc.cloud.common.dto.query.PagingResponse;
import com.anycc.cloud.common.exception.AnyccRuntimeException;
import com.anycc.cloud.common.util.DynamicQuery;
import com.anycc.cloud.common.util.PagingUtil;
import com.anycc.cloud.common.util.PatternUtil;
import com.anycc.cloud.core.entity.Permission;
import com.anycc.cloud.core.entity.Role;
import com.anycc.cloud.core.repository.RoleRepository;
import com.anycc.cloud.core.service.AccountService;
import com.anycc.cloud.core.service.RoleService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import static com.anycc.cloud.common.constant.CacheNameConstant.FIELD_CACHE_MENU;

/**
 * role service impl
 */
@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private AccountService accountService;

    @Override
    public Role create(Role role) {
        checkRoleNameAndSn(role);
        Assert.isNull(role.getId(), "新增角色时，角色ID必须为空");
        roleRepository.save(role);
        return null;
    }

    @Override
    public void deletePermissionsByModuleId(String moduleId) {
        List<Role> roleList = roleRepository.findByPermissionsModuleId(moduleId);
        if (!roleList.isEmpty()) {
            List<Role> newRoleList = filterRoleByModuleId(moduleId, roleList);//排除角色中被删除模块的权限
            roleRepository.saveAll(newRoleList);
        }

    }

    @Override
    @Transactional
    public void deletePermissions(List<String> deletePermissionIds) {
        List<Role> roleList = roleRepository.findByPermissionsIdIn(deletePermissionIds);
        List<Role> newRoleList = new ArrayList<>(roleList.size());
        roleList.forEach(role -> {
            List<Permission> newPermissions = removeDeletedPermissions(deletePermissionIds, role.getPermissions());
            role.setPermissions(newPermissions);
            newRoleList.add(role);
        });
        roleRepository.saveAll(newRoleList);
    }

    @Override
    public PagingResponse<Role> findByPaging(Role role, PagingRequest pagingRequest) {
        Page<Role> page = roleRepository
                .findAll(new DynamicQuery<Role>().build((predicates, root, query, cb) -> {
                    if (StringUtils.isNotBlank(role.getName())) {
                        predicates.add(cb.like(root.get(Role.FIELD_NAME), PatternUtil.trimLike(role.getName())));
                    }
                }), PagingUtil.buildPageRequest(pagingRequest));
        return PagingUtil.buildPagingResponse(pagingRequest, page);
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_MENU},allEntries=true)//allEntries表示清除该key下所有元素
    public void delete(String id) {
        if (roleRepository.findById(id).orElse(null) == null) {
            throw new AnyccRuntimeException("core.exceptions.role.not_existed");
        } else {
            accountService.deleteRole(id);
            roleRepository.deleteById(id);
        }
    }

    @Override
    public Role findById(String id) {
        return roleRepository.findById(id).orElse(new Role());
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_MENU},allEntries=true)//allEntries表示清除该key下所有元素
    public Role update(Role role) {
        checkRoleNameAndSn(role);
        Assert.notNull(role.getId(), "更新角色时，角色ID不能为空");
        return roleRepository.save(role);
    }

    @Override
    public List<Role> findAllByNameAsc() {
        return roleRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));
    }

    private void checkRoleNameAndSn(Role role) {
        if (StringUtils.isBlank(role.getName())) {
            throw new AnyccRuntimeException("core.exceptions.role.name_required");
        } else if (StringUtils.isBlank(role.getSn())) {
            throw new AnyccRuntimeException("core.exceptions.role.sn_required");
        } else {
            List<Role> dbRoles = roleRepository.findByNameOrSn(role.getName(), role.getSn());
            Iterator<Role> iterator = dbRoles.iterator();
            Role dbRole;
            do {
                if (!iterator.hasNext()) {
                    return;
                }
                dbRole = iterator.next();
            } while (StringUtils.equals(dbRole.getId(), role.getId()));

            throw new AnyccRuntimeException("core.exceptions.role_or_name_existed");
        }
    }

    private List<Role> filterRoleByModuleId(String moduleId, List<Role> roleList) {
        List<Role> resultList = new ArrayList<>(roleList.size());
        roleList.forEach(role -> {
            List<Permission> newPermissions = new ArrayList<>();
            role.getPermissions().forEach(permission -> {
                if (!StringUtils.equals(permission.getModule().getId(), moduleId)) {
                    newPermissions.add(permission);
                }
            });
            role.setPermissions(newPermissions);
            resultList.add(role);
        });
        return resultList;
    }

    private List<Permission> removeDeletedPermissions(List<String> delPermissionIdList, List<Permission> dbPermissions) {
        List<Permission> newPermissions = new ArrayList<>();

        for (Permission dbPerm : dbPermissions) {
            boolean isDeleted = false;
            for (String delPermId : delPermissionIdList) {
                if (dbPerm.getId().equals(delPermId)) {
                    isDeleted = true;
                    break;
                }
            }
            if (!isDeleted) {
                newPermissions.add(dbPerm);
            }
        }
        return newPermissions;
    }
}

